/**
 * This sample code is made available as part of the book "Digital Image
 * Processing - An Algorithmic Introduction using Java" by Wilhelm Burger
 * and Mark J. Burge, Copyright (C) 2005-2008 Springer-Verlag Berlin, 
 * Heidelberg, New York.
 * Note that this code comes with absolutely no warranty of any kind.
 * See http://www.imagingbook.com for details and licensing conditions.
 * 
 * Date: 2013/05/01
 */

package color;

/** Static methods for converting between RGB and HSV color spaces.
*/

public class RgbHsv {

	public static float[] RGBtoHSV (int[] RGB, float[] HSV) {
		int R = RGB[0];
		int G = RGB[1]; 
		int B = RGB[2];
		// R,G,B in [0,255]
		float H = 0, S = 0, V = 0;
		float cMax = 255.0f;
		int cHi = Math.max(R,Math.max(G,B));	// highest color value
		int cLo = Math.min(R,Math.min(G,B));	// lowest color value
		int cRng = cHi - cLo;				    // color range
		
		// compute value V
		V = cHi / cMax;
		
		// compute saturation S
		if (cHi > 0)
			S = (float) cRng / cHi;

		// compute hue H
		if (cRng > 0) {	// hue is defined only for color pixels
			float rr = (float)(cHi - R) / cRng;
			float gg = (float)(cHi - G) / cRng;
			float bb = (float)(cHi - B) / cRng;
			float hh;
			if (R == cHi)                      // r is highest color value
				hh = bb - gg;
			else if (G == cHi)                 // g is highest color value
				hh = rr - bb + 2;
			else                               // b is highest color value
				hh = gg - rr + 4;
			if (hh < 0)
				hh= hh + 6;
			H = hh / 6;
		}
		if (HSV == null)	// create a new HSV array if needed
			HSV = new float[3];
		HSV[0] = H; HSV[1] = S; HSV[2] = V;
		return HSV;
	}
	
	public static int[] HSVtoRGB (float[] HSV, int[] RGB) {
		float h = HSV[0]; 
		float s = HSV[1]; 
		float v = HSV[2];
		// h,s,v in [0,1]
		float r = 0, g = 0, b = 0;
		float hh = (6 * h) % 6;                 
		int   c1 = (int) hh;                     
		float c2 = hh - c1;
		float x = (1 - s) * v;
		float y = (1 - (s * c2)) * v;
		float z = (1 - (s * (1 - c2))) * v;	
		switch (c1) {
			case 0: r = v; g = z; b = x; break;
			case 1: r = y; g = v; b = x; break;
			case 2: r = x; g = v; b = z; break;
			case 3: r = x; g = y; b = v; break;
			case 4: r = z; g = x; b = v; break;
			case 5: r = v; g = x; b = y; break;
		}
		
		int R = Math.min((int)(r * 255), 255);
		int G = Math.min((int)(g * 255), 255);
		int B = Math.min((int)(b * 255), 255);
		if (RGB == null)	// create a new RGB array if needed
			RGB = new int[3];
		RGB[0] = R; RGB[1] = G; RGB[2] = B;
		return RGB;
	}
	
	public static int HSVtoRGB (float h, float s, float v) {
		// h,s,v in [0,1]
		float r = 0, g = 0, b = 0;
		float hh = (6 * h) % 6;                 
		int   c1 = (int) hh;                     
		float c2 = hh - c1;
		float x = (1 - s) * v;
		float y = (1 - (s * c2)) * v;
		float z = (1 - (s * (1 - c2))) * v;	
		switch (c1) {
			case 0: r = v; g = z; b = x; break;
			case 1: r = y; g = v; b = x; break;
			case 2: r = x; g = v; b = z; break;
			case 3: r = x; g = y; b = v; break;
			case 4: r = z; g = x; b = v; break;
			case 5: r = v; g = x; b = y; break;
		}
		
		int R = Math.min((int)(r * 255), 255);
		int G = Math.min((int)(g * 255), 255);
		int B = Math.min((int)(b * 255), 255);
		
		// create int-packed RGB-color:
		int rgb = ((R & 0xff) << 16) | ((G & 0xff) << 8) | B & 0xff;
		return rgb;
	}

}
